/*****************************************************************************************
   
   Copyright (c) Microsoft Corporation. All rights reserved.

   Use of this code sample is subject to the terms of the Microsoft
   Permissive License, a copy of which should always be distributed with
   this file.  You can also access a copy of this license agreement at:
   http://www.microsoft.com/resources/sharedsource/licensingbasics/permissivelicense.mspx

 ****************************************************************************************/

using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Windows.Forms;

namespace GrooveWebServicesV12Controls
{
	/// <summary>
	/// Summary description for ContactAwarenessViewer.
	/// </summary>
	[System.Runtime.InteropServices.Guid("103B7730-DE65-3F33-80AE-D65A93CBE92D")]
	[System.Drawing.ToolboxBitmapAttribute(typeof(ContactAwarenessViewer), "ContactAwarenessViewer.ico")]
	public class ContactAwarenessViewer : System.Windows.Forms.UserControl
	{
		#region COM Registration Functions
		
		//  For more information, see Adam Nathan's book ".NET and COM", pp 471-477
		[System.Runtime.InteropServices.ComRegisterFunction]
		private static void ComRegisterFunction(System.Type i_Type)
		{
			Microsoft.Win32.RegistryKey CLSIDRegistryKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("CLSID\\" + i_Type.GUID.ToString("B"), true);
			CLSIDRegistryKey.CreateSubKey("Control");
			CLSIDRegistryKey.CreateSubKey("Implemented Categories\\{40FC6ED4-2438-11CF-A3DB-080036F12502}");
			
			Microsoft.Win32.RegistryKey MiscStatusRegistryKey = CLSIDRegistryKey.CreateSubKey("MiscStatus");
			MiscStatusRegistryKey.SetValue("","131457");

			Microsoft.Win32.RegistryKey TypeLibRegistryKey = CLSIDRegistryKey.CreateSubKey("TypeLib");
			string TypeLibGuid = System.Runtime.InteropServices.Marshal.GetTypeLibGuidForAssembly(i_Type.Assembly).ToString("B");
			TypeLibRegistryKey.SetValue("", TypeLibGuid);

			string Version = i_Type.Assembly.GetName().Version.Major.ToString() + "." + i_Type.Assembly.GetName().Version.Minor.ToString();
			if (Version == "0.0")
				Version = "1.0";

			Microsoft.Win32.RegistryKey VersionRegistryKey = CLSIDRegistryKey.CreateSubKey("Version");
			VersionRegistryKey.SetValue("", Version);

			CLSIDRegistryKey.Close();
		}

		[System.Runtime.InteropServices.ComUnregisterFunction]
		private static void ComUnregisterFunction(System.Type i_Type)
		{
			try
			{
				Microsoft.Win32.Registry.ClassesRoot.DeleteSubKeyTree("CLSID\\" + i_Type.GUID.ToString("B"));
			}
			catch (ArgumentException)
			{
				//  Ignore exception thrown if key doesn't exist
			}
		}

		#endregion

		private GrooveWebServicesV12Helpers.Context m_Context;

		private System.Collections.SortedList m_ContactTreeNodeSortedList;

		private GrooveWebServicesV12Helpers.Account m_Account;
		private GrooveWebServicesV12Helpers.Identity m_Identity;

		public System.Windows.Forms.TreeView TreeView;

		private System.Windows.Forms.ImageList imageList1;
		private System.ComponentModel.IContainer components;

		private System.EventHandler m_ContextMenuEventHandler;

		private System.Windows.Forms.ContextMenu m_ContextMenu;
		private System.Windows.Forms.MenuItem m_SendMessageMenuItem;
		private System.Windows.Forms.MenuItem m_InviteToWorkspaceMenuItem;
		private System.Windows.Forms.MenuItem m_InviteToInstantChatMenuItem;
		private System.Windows.Forms.MenuItem m_PropertiesMenuItem;

		private GrooveWebServicesV12Controls.ContactTreeNode m_CurrentContactTreeNode;

		private delegate void AddContactTreeNodeDelegate(GrooveWebServicesV12Helpers.Contact i_Contact);
		private delegate void UpdateContactTreeNodeDelegate(GrooveWebServicesV12Helpers.Contact i_Contact);
		private delegate void RemoveContactTreeNodeDelegate(string i_ContactURI);

		private AddContactTreeNodeDelegate m_AddContactTreeNodeDelegate;
		private UpdateContactTreeNodeDelegate m_UpdateContactTreeNodeDelegate;
		private RemoveContactTreeNodeDelegate m_RemoveContactTreeNodeDelegate;

		public ContactAwarenessViewer()
		{
            InitializeComponent();
        }

        public void Start()
        {
            Start(null);
        }

		public void Start(GrooveWebServicesV12Helpers.Context i_Context)
		{
            Start(null, false);
        }

        public void Start(GrooveWebServicesV12Helpers.Context i_Context, Boolean i_EnableContextMenu)
        {
			if (i_Context == null)
				m_Context = new GrooveWebServicesV12Helpers.Context();
			else
				m_Context = i_Context;
			
			m_ContactTreeNodeSortedList = new System.Collections.SortedList();

            if (i_EnableContextMenu)
            {
                //  Create context menu and menu items
                m_ContextMenuEventHandler = new System.EventHandler(ContextMenu_OnClick);
                m_SendMessageMenuItem = new System.Windows.Forms.MenuItem("Send Message...", m_ContextMenuEventHandler);
                m_InviteToWorkspaceMenuItem = new System.Windows.Forms.MenuItem("Invite to Workspace...", m_ContextMenuEventHandler);
                m_InviteToInstantChatMenuItem = new System.Windows.Forms.MenuItem("Invite to Instant Chat", m_ContextMenuEventHandler);
                m_PropertiesMenuItem = new System.Windows.Forms.MenuItem("Properties...", m_ContextMenuEventHandler);

                System.Windows.Forms.MenuItem[] MenuItems = { m_SendMessageMenuItem, m_InviteToWorkspaceMenuItem, m_InviteToInstantChatMenuItem, m_PropertiesMenuItem };
                m_ContextMenu = new System.Windows.Forms.ContextMenu(MenuItems);
                
                this.TreeView.SelectedImageIndex = 2;
            }

			m_AddContactTreeNodeDelegate = new GrooveWebServicesV12Controls.ContactAwarenessViewer.AddContactTreeNodeDelegate(AddContactTreeNode);
			m_UpdateContactTreeNodeDelegate = new GrooveWebServicesV12Controls.ContactAwarenessViewer.UpdateContactTreeNodeDelegate(UpdateContactTreeNode);
			m_RemoveContactTreeNodeDelegate = new GrooveWebServicesV12Controls.ContactAwarenessViewer.RemoveContactTreeNodeDelegate(RemoveContactTreeNode);
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
					components.Dispose();

				//  Unsubscribe for contact events if necessary
				if (m_Account != null)
				{
					m_Account.OnContactAddedEvent -= new GrooveWebServicesV12Helpers.Account.OnContactAddedDelegate(Account_OnContactAdded);
					m_Account.OnContactUpdatedEvent -= new GrooveWebServicesV12Helpers.Account.OnContactUpdatedDelegate(Account_OnContactUpdated);
					m_Account.OnContactRemovedEvent -= new GrooveWebServicesV12Helpers.Account.OnContactRemovedDelegate(Account_OnContactRemoved);
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(ContactAwarenessViewer));
			this.TreeView = new System.Windows.Forms.TreeView();
			this.imageList1 = new System.Windows.Forms.ImageList(this.components);
			this.SuspendLayout();
			// 
			// TreeView
			// 
			this.TreeView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
			this.TreeView.Dock = System.Windows.Forms.DockStyle.Fill;
			this.TreeView.HideSelection = false;
			this.TreeView.ImageList = this.imageList1;
			this.TreeView.Location = new System.Drawing.Point(0, 0);
			this.TreeView.Name = "TreeView";
			//this.TreeView.SelectedImageIndex = 2;
			this.TreeView.ShowLines = false;
			this.TreeView.ShowPlusMinus = false;
			this.TreeView.ShowRootLines = false;
			this.TreeView.Size = new System.Drawing.Size(208, 216);
			this.TreeView.Sorted = true;
			this.TreeView.TabIndex = 0;
			this.TreeView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.TreeView_MouseDown);
			this.TreeView.DoubleClick += new System.EventHandler(this.TreeView_DoubleClick);
			// 
			// imageList1
			// 
			this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
			this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
			this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
			// 
			// ContactAwarenessViewer
			// 
			this.Controls.Add(this.TreeView);
			this.Name = "ContactAwarenessViewer";
			this.Size = new System.Drawing.Size(208, 216);
			this.Load += new System.EventHandler(this.ContactAwarenessViewer_Load);
			this.ResumeLayout(false);

		}
		#endregion

		[System.ComponentModel.Browsable(false)]
		public GrooveWebServicesV12Helpers.Account Account
		{
			get
			{
				return m_Account;
			}
			set
			{
				if ((value != null) && !this.DesignMode)
				{
					GrooveWebServicesV12Helpers.Account Account = (GrooveWebServicesV12Helpers.Account)value;
					
					//  See if we have already cached a reference to account
					if (m_Account != null)
					{
						//  If cached value is same as new value, just exit now
						if (m_Account.URI == Account.URI)
							return;

						//  Unsubscribe for contact events
						m_Account.OnContactAddedEvent -= new GrooveWebServicesV12Helpers.Account.OnContactAddedDelegate(Account_OnContactAdded);
						m_Account.OnContactUpdatedEvent -= new GrooveWebServicesV12Helpers.Account.OnContactUpdatedDelegate(Account_OnContactUpdated);
						m_Account.OnContactRemovedEvent -= new GrooveWebServicesV12Helpers.Account.OnContactRemovedDelegate(Account_OnContactRemoved);
					}

					//  Cache reference to account
					m_Account = value;

					//  Subscribe for contact events
					m_Account.OnContactAddedEvent += new GrooveWebServicesV12Helpers.Account.OnContactAddedDelegate(Account_OnContactAdded);
					m_Account.OnContactUpdatedEvent += new GrooveWebServicesV12Helpers.Account.OnContactUpdatedDelegate(Account_OnContactUpdated);
					m_Account.OnContactRemovedEvent += new GrooveWebServicesV12Helpers.Account.OnContactRemovedDelegate(Account_OnContactRemoved);

					//  If only one identity for account, assign identity now
					GrooveWebServicesV12Helpers.Identity[] Identities = m_Account.Identities;
					if (Identities.Length == 1)
						m_Identity = Identities[0];

					PopulateContacts();
				}
			}
		}

		[System.ComponentModel.Browsable(false)]
		public GrooveWebServicesV12Helpers.Identity Identity
		{
			get
			{
				return m_Identity;
			}
			set
			{
				if ((value != null) && !this.DesignMode)
				{
					GrooveWebServicesV12Helpers.Identity Identity = (GrooveWebServicesV12Helpers.Identity)value;
					
					//  See if we have already cached a reference to identity
					if (m_Identity != null)
					{
						//  If cached value is same as new value, just exit now
						if (m_Identity.URI == Identity.URI)
							return;
					}

					//  Cache reference to identity
					m_Identity = value;
				}
			}
		}

		private void PopulateContacts()
		{
			//  Clear treeview, sorted list and array list
			TreeView.Nodes.Clear();
			m_ContactTreeNodeSortedList.Clear();

			//  Iterate through contacts
			GrooveWebServicesV12Helpers.Contact[] Contacts = m_Account.PersonalContacts;
			foreach (GrooveWebServicesV12Helpers.Contact Contact in Contacts)
			{
				Application.DoEvents();

				//  Asynchronously add Contact tree node
				object[] Args = {Contact};
				BeginInvoke(m_AddContactTreeNodeDelegate, Args);
			}
		}

		private void AddContactTreeNode(GrooveWebServicesV12Helpers.Contact i_Contact)
		{
			GrooveWebServicesV12Controls.ContactTreeNode ContactTreeNode = null;

			lock (m_ContactTreeNodeSortedList)
			{
				//  Check for existing node, if found just exit now
				ContactTreeNode = (GrooveWebServicesV12Controls.ContactTreeNode)m_ContactTreeNodeSortedList[i_Contact.URI];
				if (ContactTreeNode != null)
					return;

				ContactTreeNode = new GrooveWebServicesV12Controls.ContactTreeNode(i_Contact);
				ContactTreeNode.Text = i_Contact.Name;

				if (i_Contact.Awareness == "Online")
					ContactTreeNode.ImageIndex = 0;
				else
					ContactTreeNode.ImageIndex = 1;

				TreeView.Nodes.Add(ContactTreeNode);

				//  Add new node to sorted list
				m_ContactTreeNodeSortedList[i_Contact.URI] = ContactTreeNode;
			}
		}

		private void UpdateContactTreeNode(GrooveWebServicesV12Helpers.Contact i_Contact)
		{
			lock (m_ContactTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				GrooveWebServicesV12Controls.ContactTreeNode ContactTreeNode = (GrooveWebServicesV12Controls.ContactTreeNode)m_ContactTreeNodeSortedList[i_Contact.URI];
				if (ContactTreeNode == null)
					return;

				ContactTreeNode.Text = i_Contact.Name;
				if (i_Contact.Awareness == "Online")
					ContactTreeNode.ImageIndex = 0;
				else
					ContactTreeNode.ImageIndex = 1;
			}
		}

		private void RemoveContactTreeNode(string i_ContactURI)
		{
			lock (m_ContactTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_ContactTreeNodeSortedList[i_ContactURI] == null)
					return;

				//  Remove tree node
				System.Windows.Forms.TreeNode TreeNode = (System.Windows.Forms.TreeNode)m_ContactTreeNodeSortedList[i_ContactURI];
				TreeNode.Remove();

				//  Remove node from sorted list
				m_ContactTreeNodeSortedList.Remove(i_ContactURI);
			}
		}

		private void ContactAwarenessViewer_Load(object sender, System.EventArgs e)
		{
			if (this.DesignMode)
			{
				//  Create mockup tree
				System.Windows.Forms.TreeNode ContactTreeNode = new System.Windows.Forms.TreeNode("John Smith");
				ContactTreeNode.ImageIndex = 0;
				TreeView.Nodes.Add(ContactTreeNode);

				ContactTreeNode = new System.Windows.Forms.TreeNode("Susan Smith");
				ContactTreeNode.ImageIndex = 1;
				TreeView.Nodes.Add(ContactTreeNode);
			}
			else
			{
				//  If there is only one account, we can set the Account property now
				GrooveWebServicesV12Helpers.Account[] Accounts = GrooveWebServicesV12Helpers.Account.GetAccounts(m_Context);
				if (Accounts.Length == 1)
				{
					this.Account = Accounts[0];

					//  If there is only one identity, we can set the Identity property now
					GrooveWebServicesV12Helpers.Identity[] Identities = Account.Identities;
					if (Identities.Length == 1)
						this.Identity = Identities[0];
				}
			}
		}

		private void ContextMenu_OnClick(object sender, EventArgs e)
		{
			System.Windows.Forms.MenuItem MenuItem = (System.Windows.Forms.MenuItem)sender;
			switch (MenuItem.Index)
			{
				//  Send Message
				case 0:
				{
					try
					{
						GrooveWebServicesV12Helpers.Local.OpenSendInstantMessageWindow
							(
							m_Identity,
							m_CurrentContactTreeNode.Contact
							);
					}
					catch (Exception ex)
					{
						System.Diagnostics.Debug.WriteLine("OpenSendInstantMessageWindow failed: " + ex.Message);
					}

					break;
				}

				//  Invite to Chat
				case 2:
				{
					try
					{
						GrooveWebServicesV12Helpers.Local.SendInvitationToChat
							(
							m_Identity,
							m_CurrentContactTreeNode.Contact
							);
					}
					catch (Exception ex)
					{
						System.Diagnostics.Debug.WriteLine("SendInvitationToChat failed: " + ex.Message);
					}

					break;
				}

				//  Properties
				case 3:
				{
					try
					{
						GrooveWebServicesV12Helpers.Local.OpenContactPropertiesViewer
							(
							m_Identity,
							m_CurrentContactTreeNode.Contact
							);
					}
					catch (Exception ex)
					{
						System.Diagnostics.Debug.WriteLine("OpenVCardViewer failed: " + ex.Message);
					}

					break;
				}

				default:
				{
					break;
				}
			}
		}

		private void InviteToSpaceMenuItem_OnClick(object sender, EventArgs e)
		{
			GrooveWebServicesV12Controls.SpaceMenuItem SpaceMenuItem = (GrooveWebServicesV12Controls.SpaceMenuItem)sender;

			try
			{
				GrooveWebServicesV12Helpers.Local.OpenSendInvitationWindow(SpaceMenuItem.Space);
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine("OpenSendInvitationWindow failed: " + ex.Message);
			}
		}

		#region Contact Event Handlers

		private void Account_OnContactAdded(GrooveWebServicesV12Helpers.Contact i_Contact)
		{
			System.Diagnostics.Debug.WriteLine("OnContactAdded: " + i_Contact.Name);
			
			lock (m_ContactTreeNodeSortedList)
			{
				//  Check for existing node, if found just exit now
				if (m_ContactTreeNodeSortedList[i_Contact.URI] != null)
					return;

				//  Get contact tree node
				GrooveWebServicesV12Controls.ContactTreeNode ContactTreeNode = (GrooveWebServicesV12Controls.ContactTreeNode)m_ContactTreeNodeSortedList[i_Contact.URI];

				//  Asynchronously add Contact tree node
				object[] Args = {i_Contact};
				BeginInvoke(m_AddContactTreeNodeDelegate, Args);
			}
		}

		private void Account_OnContactUpdated(GrooveWebServicesV12Helpers.Contact i_Contact)
		{
			System.Diagnostics.Debug.WriteLine("OnContactUpdated: " + i_Contact.Name);

			lock (m_ContactTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_ContactTreeNodeSortedList[i_Contact.URI] == null)
					return;

				//  Get contact tree node
				GrooveWebServicesV12Controls.ContactTreeNode ContactTreeNode = (GrooveWebServicesV12Controls.ContactTreeNode)m_ContactTreeNodeSortedList[i_Contact.URI];

				//  Asynchronously update Contact tree node
				object[] Args = {i_Contact};
				BeginInvoke(m_UpdateContactTreeNodeDelegate, Args);
			}
		}

		private void Account_OnContactRemoved(string i_ContactURI)
		{
			System.Diagnostics.Debug.WriteLine("OnContactRemoved: " + i_ContactURI);

			lock (m_ContactTreeNodeSortedList)
			{
				//  Check for existing node, if not found just exit now
				if (m_ContactTreeNodeSortedList[i_ContactURI] == null)
					return;
			
				//  Asynchronously remove Contact tree node
				object[] Args = {i_ContactURI};
				BeginInvoke(m_RemoveContactTreeNodeDelegate, Args);
			}
		}

		#endregion

		private void TreeView_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			System.Windows.Forms.TreeNode TreeNode = TreeView.GetNodeAt(e.X, e.Y);
			if (TreeNode == null)
				return;

			TreeView.SelectedNode = TreeNode;
			m_CurrentContactTreeNode = (GrooveWebServicesV12Controls.ContactTreeNode)TreeNode;

			if (e.Button == System.Windows.Forms.MouseButtons.Right && m_ContextMenu != null)
			{
				//  Remove existing invite to space menu item and 
				//  reconstruct it
				m_ContextMenu.MenuItems.Remove(m_InviteToWorkspaceMenuItem);

				m_InviteToWorkspaceMenuItem = new System.Windows.Forms.MenuItem("Invite to Workspace...", m_ContextMenuEventHandler);
				m_ContextMenu.MenuItems.Add(1, m_InviteToWorkspaceMenuItem);

				//  Get list of spaces and populate submenu items
				GrooveWebServicesV12Helpers.Space[] Spaces = m_Identity.StandardSpaces;
				foreach (GrooveWebServicesV12Helpers.Space Space in Spaces)
				{
					GrooveWebServicesV12Controls.SpaceMenuItem SpaceMenuItem = new GrooveWebServicesV12Controls.SpaceMenuItem(Space);
					SpaceMenuItem.Click += new System.EventHandler(InviteToSpaceMenuItem_OnClick);
					m_InviteToWorkspaceMenuItem.MenuItems.Add(SpaceMenuItem);
				}

				m_ContextMenu.Show(TreeView, new System.Drawing.Point(e.X, e.Y));
			}
		}

		private void TreeView_DoubleClick(object sender, System.EventArgs e)
		{
            if (m_ContextMenu != null)
            {
                try
                {
                    GrooveWebServicesV12Helpers.Local.OpenSendInstantMessageWindow
                        (
                        m_Identity,
                        m_CurrentContactTreeNode.Contact
                        );
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("OpenSendInstantMessageWindow failed: " + ex.Message);
                }
            }
		}
	}
}
